

package algoritmogenetico;

import java.util.*; 
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.logging.Level;
import java.util.logging.Logger;

    
public class AlgoritmoGenetico {
   
    static int opcion = 3;             //Número de función a optimizar
    static int numGen = 10000;             //Número de generaciones
    static int numInds = 500;           //Número de individuos
    static int bitsDec = 5;            //Bits para decimales
    static int bitsEnt = 3;            //Bits para enteros
    static int numVar = 50;             //Número de variables por genoma
    static int semilla = 210195;       //Semilla para los números aleatorios
    static int normaliza = 1;          //Normaliza indica el tipo de función para normalizar 1: linear offset
    static double probXOver = 0.9;     //Probabilidad de cross over
    static double probMuta = 0.005;    //Probabilidad de mutación
    
    
    public static void Menu(Scanner scan){
        int modificaParam = 1;
        ImprimeParametros();
        System.out.println("\n¿Quieres modificar algún parámetro? (1=sí, 0=no)");
        modificaParam = scan.nextInt();
        while(modificaParam == 1){
            ModificaParametros();
            ImprimeParametros();
            System.out.println("\n¿Quieres modificar algún parámetro? (1=sí, 0=no)");
            modificaParam = scan.nextInt();
        }
    }
    
    public static void ImprimeParametros(/*Scanner scan, int opcion, int numGen, int numInds, int bitsDec, int bitsEnt, int numVar, int semilla, int normaliza, double probxover, double probmuta*/){
        System.out.println("\nParámetros del algoritmo: ");
        System.out.println(" 1.Función a optimizar: "+opcion);
        System.out.println(" 2.Número de generaciones: "+numGen);
        System.out.println(" 3.Número de individuos: "+numInds);
        System.out.println(" 4.Bits para decimales: "+bitsDec);
        System.out.println(" 5.Bits para enteros: "+bitsEnt);
        System.out.println(" 6.Número de variables por genoma: "+numVar);
        System.out.println(" 7.Semilla para los números aleatorios: "+semilla);
        System.out.println(" 8.Normaliza indica el tipo de función para normalizar (1 para linear offset): "+normaliza);
        System.out.println(" 9.Probabilidad de cross over: "+probXOver);
        System.out.println("10.Probabilidad de mutación: "+probMuta);
    }
    
    public static void ModificaParametros(){
        Scanner sca = new Scanner(System.in);
        int modifica;
        System.out.println("\n¿Qué parámetro quieres modificar?");
        int param = sca.nextInt();
        System.out.println("¿Cuál es el nuevo valor?");
        switch (param){
             case 1: opcion = sca.nextInt();
                    break;
             case 2: numGen = sca.nextInt();
                    break;
             case 3: numInds = sca.nextInt();
                    break;    
             case 4: bitsDec = sca.nextInt();
                    break;
             case 5: bitsEnt = sca.nextInt();
                    break;
             case 6: numVar = sca.nextInt();
                    break;
             case 7: semilla = sca.nextInt();
                    break;
             case 8: normaliza = sca.nextInt();
                     System.out.println("Este parámetro no se puede modificar ahora.");
                     normaliza = 1;
                    break;
             case 9: probXOver = sca.nextDouble();
                    break;
             case 10: probMuta = sca.nextDouble();
                    break;
            }
    }
    
    public static void main(String[] args) {    
    Scanner scan = new Scanner(System.in); 
    int otravez = 1;
    String renglon = "N,G,Pm,Pxo,NumVar,";
    for(int i=0; i<numVar; i++){
        renglon = renglon+"x"+i+",";
    }
    renglon = renglon+"fitness\n";
    while(otravez == 1){
        Random aleatorio = new Random();        //Inicialización de generador de números pseudoaleaotrios
        aleatorio.setSeed(semilla);             //Inicializar la semilla del generador.
        
        Menu(scan);
        
    //Declarar las variables tipo Población
        Poblacion pob1 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);
        Poblacion pob3 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);
        Poblacion pob2 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);

    //Crear la población inicial
        pob1.CreaPoblacionInicial();
        /*//Quitar este comentario para ver los genomas de la población inicial
        System.out.println("\nImprimiendo población Inicial");
        pob1.ImprimeGenomas();*/

    //Iterar el proceso evolutivo
        for(int i = 0; i< numGen; i++){
        //Encontrar el fitness, normalizarlo, ordenarlo para construir su cdf y hacer selección proporcional 
            pob1.Fitness(opcion);
            pob1.NormalizaFitness(normaliza);
            pob1.OrdenaPorCDF();
            
        //Los individuos seleccionados van a conformar la población 2
            pob2 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);
            pob2.SeleccionProporcional(pob1); //Esta selección tiene elitismo de 1.
            /* //Quitar este comentario para ver la población seleccionada
            System.out.println("\nImprimiendo población "+i+" después de seleccionar.");
            pob2.ImprimePoblacionConValores();*/

        //Hacemos crossover y mutación.
            pob3 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);
            pob2.Xover(pob3);//La población con xover queda en pob3.
            pob3.Muta();
            /* //Quitar este comentario para ver la población ya con crossover y mutación.
            System.out.println("\nImprimiendo población "+i+" después de mutar.");
            pob3.ImprimePoblacionConValores();*/
            pob1 = new Poblacion(numInds,bitsEnt,bitsDec,numVar,probXOver,probMuta,aleatorio);
            pob1 = new Poblacion(pob3);
            /* //Quitar este comentario para ver la población anterior copiada ahora en la variable pob1.
            System.out.println("\nImprimiendo población recién copiada.");
            pob1.ImprimePoblacionConValores();*/

        }
    //Volvemos a sacar el fitness, a normalizar y a ordenar por cdf
        pob3.Fitness(opcion);
        pob3.NormalizaFitness(normaliza);
        pob3.OrdenaPorCDF();
        /* //Quitar este comentario para ver la población final
        System.out.println("Imprimieno población 3");
        pob3.ImprimePoblacionConValores();*/

    //Imprimir el resutlado en pantalla
        pob3.ImprimeOptimo();
        
        
        
        
        
        ////////////////////////
        pob3.individuos[0].ImprimeGenoma();
        //pob3.individuos[0].Deceptive(12, 22);
        
        
        /////////////////////////
        double valores[] = pob3.individuos[0].RegresaValores();
        
        
    //Guardar los valores para imprimir el resultado en archivo
        renglon = renglon+numInds+","+numGen+","+probMuta+","+probXOver+","+numVar;
        for(int i = 0; i<numVar; i++){
            renglon = renglon+","+valores[i];
        }
        renglon = renglon +","+ pob3.RegresaOptimoString()+"\n";
        
        
        System.out.println("\n¿Quieres que vuelva a correr? (1=sí, 0=no)");
        otravez = scan.nextInt();
        }
        
    //En esta parte se imprimen en un archivo csv los valores de Número de individuos,
    //número de generaciones, prob. mutación, prob. crossover y fitness.
        FileWriter fw;
            try {
                fw = new FileWriter("AlgoritmoGenetico\\DeJong4.csv");
                PrintWriter pw = new PrintWriter(fw);
                pw.print(renglon);
                pw.flush();
                pw.close();
                fw.close();
            } catch (IOException ex) {
                Logger.getLogger(AlgoritmoGenetico.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("No imprimió archivo.");
            }
    
    }
}
